package simtester.cloud;

import static org.junit.Assert.*;

import com.amazonaws.AmazonServiceException
import com.amazonaws.services.ec2.AmazonEC2Client
import groovy.mock.interceptor.StubFor
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test

class CloudTests {
    static testFolder
    static testCredentials
    static testEndpoint
    static testAuthkey
    static testScript
    
    @BeforeClass
    static void setUpClass() {
        //TODO: Update SimTesterConfig.groovy to the new one used by :server
        def config = new ConfigSlurper().parse(new File('conf/SimTesterConfig.groovy').toURI().toURL())
        testFolder      = config.test.env
        testCredentials = config.aws.credentialsfile
        testEndpoint    = config.aws.endpoint
        testAuthkey     = config.aws.key
        
        testScript = '''\
package simtester.agent
import geb.*
class AgentScript {
  static runtest() {
    Browser.drive {
      go 'http://www.google.com'
      println "Title: $title"
      assert 'Google' == title
    }
  }
}'''
    }

    @Before
    public void setUp() throws Exception {
    }

    @After
    public void tearDown() throws Exception {
        new File(testFolder).eachFile { file ->
            if ( !(file.name =~ /.svn/) ) {
                new AntBuilder().delete(dir: file.toString())
            }
        }
    }
    
    @Test
    void createBlankTestAgent() throws Exception {
        def cloud = new Cloud(type:     'local',
                              env:      testFolder,
                              creds:    testCredentials,
                              endpoint: testEndpoint,
                              key:      testAuthkey)
        
        def agentjar = new File('resources/agent.jar')
        def url = 'http://localhost:8080/server/'
        def instance = cloud.createBlankTestAgent(agentpkg: agentjar)
        
        def agentDir = "$testFolder/agent1"
        assert instance.id == agentDir
        
        def expectedFiles = [
            "$agentDir/agent.jar"
        ]
        
        expectedFiles.each { filename ->
            assert new File(filename).exists()
        }
        
        def unexpectedFiles = [
            "$agentDir/AgentConfig.groovy",
            "$agentDir/AgentScript.groovy"
        ]
        
        unexpectedFiles.each { filename ->
            assert ! new File(filename).exists()
        }
    }
    
    @Test
    void createTestAgent() throws Exception {
        def cloud = new Cloud(type:     'local',
                              env:      testFolder,
                              creds:    testCredentials,
                              endpoint: testEndpoint,
                              key:      testAuthkey)

        def agentjar = new File('resources/agent.jar')
        def url = 'http://localhost:8080/server/'
        def runId = 26L
        def numRepeats = 2
        def firstuser = 4
        def numUsers = 5
        def instance = cloud.createTestAgent(
            script:    testScript,
            agentpkg:  agentjar,
            url:       url,
            testrunId: runId,
            repeats:   numRepeats,
            firstuser: firstuser,
            users:     numUsers)

        def agentDir = "$testFolder/agent1"
        assert instance.id == agentDir
        
        def expectedFiles = [
            "$agentDir/agent.jar",
            "$agentDir/AgentConfig.groovy",
            "$agentDir/AgentScript.groovy"
        ]
        
        expectedFiles.each { filename ->
            assert new File(filename).exists()
        }
        
        assert new File("$agentDir/AgentScript.groovy").text == testScript
        assert new File("$agentDir/commands.txt").text =~ /java -jar agent\.jar/
        
        def configText = new File("$agentDir/AgentConfig.groovy").text
        assert configText.contains("serverurl = '$url'")
        assert configText.contains("testrunid = '$runId'")
        assert configText.contains("repeats = $numRepeats")
        assert configText.contains("firstuser = $firstuser")
        assert configText.contains("users = $numUsers")
    }
    
    @Test
    void setupTestAgent() {
        def cloud = new Cloud(type:     'local',
                              env:      testFolder,
                              creds:    testCredentials,
                              endpoint: testEndpoint,
                              key:      testAuthkey)
        
        def agentDir = "$testFolder/agent1"
        new File(agentDir).mkdirs()
        new File("$agentDir/AgentConfig.groovy").write('something\nhere')
        new File("$agentDir/AgentScript.groovy").write('something\nhere')
        
        def url = 'http://localhost:8080/server/'
        def runId = 456L
        def numRepeats = 2
        def firstuser = 3
        def numUsers = 10
        def instance = cloud.setupTestAgent(
            instanceId: agentDir,
            script:     testScript,
            url:        url,
            testrunId:  runId,
            repeats:    numRepeats,
            firstuser:  firstuser,
            users:      numUsers)
        
        assert instance.id == agentDir
        
        def expectedFiles = [
            "$agentDir/AgentConfig.groovy",
            "$agentDir/AgentScript.groovy"
        ]
        
        expectedFiles.each { filename ->
            assert new File(filename).exists()
        }
        
        assert new File("$agentDir/AgentScript.groovy").text == testScript
        assert new File("$agentDir/commands.txt").text =~ /java -jar agent\.jar/
        
        def configText = new File("$agentDir/AgentConfig.groovy").text
        assert configText.contains("serverurl = '$url'")
        assert configText.contains("testrunid = '$runId'")
        assert configText.contains("repeats = $numRepeats")
        assert configText.contains("firstuser = $firstuser")
        assert configText.contains("users = $numUsers")
    }
    
    @Test
    void setupTestAgentWithDuration() throws Exception {
        def cloud = new Cloud(type:     'local',
                              env:      testFolder,
                              creds:    testCredentials,
                              endpoint: testEndpoint,
                              key:      testAuthkey)
        
        def agentDir = "$testFolder/agent1"
        new File(agentDir).mkdirs()

        def url = 'http://localhost:8080/server/'
        def runId = 65L
        def duration = 225234
        def instance = cloud.setupTestAgent(
            instanceId:  agentDir,
            script:    testScript,
            url:       url,
            testrunId: runId,
            duration:  duration)

        def configText = new File("$agentDir/AgentConfig.groovy").text
        assert configText.contains("duration = $duration")
    }
    
    @Test
    void setupTestAgentWithTestCaseId() {
        def cloud = new Cloud(type:     'local',
                              env:      testFolder,
                              creds:    testCredentials,
                              endpoint: testEndpoint,
                              key:      testAuthkey)
        
        def agentDir = "$testFolder/agent1"
        new File(agentDir).mkdirs()
        
        def url = 'http://localhost:8080/server/'
        def runId      = 54L
        def testcaseId = 3212L
        def numRepeats = 2
        def firstuser  = 4
        def numUsers   = 5
        def instance = cloud.setupTestAgent(
            instanceId: agentDir,
            script:     testScript,
            url:        url,
            testrunId:  runId,
            testcaseId: testcaseId,
            repeats:    numRepeats,
            firstuser:  firstuser,
            users:      numUsers)
        
        def configText = new File("$agentDir/AgentConfig.groovy").text
        assert configText.contains("testcaseid = '$testcaseId'")
    }
    
    @Test
    void removeInstances() throws Exception {
        def instanceNames = ["$testFolder/agent1", "$testFolder/agent2"]

        // Create the instances
        instanceNames.each {
            new File(it).mkdirs()
        }
        
        def cloud = new Cloud(type:     'local',
                              env:      testFolder,
                              creds:    testCredentials,
                              endpoint: testEndpoint,
                              key:      testAuthkey)
        cloud.removeInstances(instanceNames)
        
        instanceNames.each {
            assert ! new File(it).exists()
        }
    }
    
    @Test
    void removeInstancesEmpty() {
        def cloud = new Cloud(creds:    testCredentials,
                              endpoint: testEndpoint,
                              key:      testAuthkey)
        
        try {
            cloud.removeInstances([])
        } catch (Exception) {
            fail 'should not throw exception'
        }
    }
    
    @Test
    void createInstanceFailsWithAmazonError() {
        def cloud = new Cloud(creds:    testCredentials,
                              endpoint: testEndpoint,
                              key:      testAuthkey)
        
        def stubEc2 = new StubFor(AmazonEC2Client)
        stubEc2.ignore.with {
            setEndpoint { arg ->  }
            runInstances { arg ->
                throw new AmazonServiceException('error')
            }
        }
        
        stubEc2.use {
            try {
                cloud.createTestAgent(
                    script:    'some script',
                    agentpkg:  new File('hello'),
                    url:       'http://localhost:8080/server/',
                    testrunId: 98L)
                fail 'CloudException not thrown'
            } catch (CloudException e) { }
            
            try {
                cloud.createInstance(type: 't1.micro', imageId: 'ami-1bd68a5e')
                fail 'CloudException not thrown'
            } catch (CloudException e) { }
        }
    }

}
